package com.sea.demo.shiro.config;

import com.sea.demo.shiro.common.ShiroRealm;
import com.sea.demo.shiro.common.ShiroSessionManager;
import com.sea.demo.shiro.common.ShiroUtils;
import com.sea.demo.shiro.filter.ShiroFormAuthenticationFilter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: 快乐在角落里
 * @Create: 2020/11/7 23:01
 * Shiro配置类
 */
@Configuration
public class ShiroConfiguration {


    @Bean
    public ShiroFilterFactoryBean shiroFilter(){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager());
        shiroFilter.setLoginUrl(loginUrl);
        shiroFilter.setFilterChainDefinitionMap(map);

        //Map<String, Filter> filterHashMap = new HashMap<>();
        //filterHashMap.put("authc",new ShiroFormAuthenticationFilter());

        //shiroFilter.setFilters(filterHashMap);

        return shiroFilter;
    }

    /**
     * 安全管理器
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        securityManager.setSessionManager(sessionManager());
        securityManager.setCacheManager(cacheManager());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    /**
     * realm
     */
    @Bean
    public ShiroRealm shiroRealm(){
        ShiroRealm shiroRealm = new ShiroRealm();
        shiroRealm.setCredentialsMatcher(matcher());
        return shiroRealm;
    }

    /**
     * 加密
     */
    @Bean
    public HashedCredentialsMatcher matcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(ShiroUtils.HASH_ALGORITHM);
        matcher.setHashIterations(ShiroUtils.HASH_ITERATIONS);
        return matcher;
    }

    /**
     * Session管理器
     */
    @Bean
    public SessionManager sessionManager(){
        ShiroSessionManager sessionManager = new ShiroSessionManager();
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    /**
     * 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(){
        RedisCacheManager cacheManager = new RedisCacheManager();
        cacheManager.setRedisManager(redisManager());
        //设置缓存的key前缀
        cacheManager.setKeyPrefix(cachePrefix);
        //设置缓存的key后缀
        cacheManager.setPrincipalIdFieldName(cacheSuffix);
        cacheManager.setExpire(cacheExpire);
        return cacheManager;
    }

    /**
     * RedisSessionDAO
     */
    @Bean
    public SessionDAO sessionDAO(){
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        sessionDAO.setExpire(sessionExpire);
        sessionDAO.setKeyPrefix(sessionPrefix);
        return sessionDAO;
    }

    /** Redis连接管理 */
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host+":"+port);
        redisManager.setPassword(password);
        redisManager.setDatabase(database);
        redisManager.setTimeout(timeout);//超时时间，尝试连接redis的时间
        return redisManager;
    }

    @Bean
    public RememberMeManager rememberMeManager(){
        CookieRememberMeManager rememberMeManager = new CookieRememberMeManager();
        rememberMeManager.setCookie(cookie());
        return rememberMeManager;
    }

    @Bean
    public Cookie cookie(){
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName(rememberMeName);
        simpleCookie.setMaxAge(maxAge);//单位秒 设置为7天
        return simpleCookie;
    }

    /**
     * shiro注解aop拦截器
     * 通过注解切面判断用户是否拥有权限
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager());
        return advisor;
    }

    /**
     * shiro开启注解支持
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        /* 设置是否直接代理Controller目标类，而不只是代理特定的接口 */
        creator.setProxyTargetClass(true);
        return creator;
    }

    /*
     * 将自定义的shiro过滤器注册到servlet容器中
     */
    /*@Bean
    public FilterRegistrationBean<Filter> filterRegistrationBean(){
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>(shiroFormAuthenticationFilter());
        registrationBean.setEnabled(false);
        return registrationBean;
    }*/

    /*
     * 自定义的shiro过滤器
     */
    /*@Bean
    public ShiroFormAuthenticationFilter shiroFormAuthenticationFilter(){
        return new ShiroFormAuthenticationFilter();
    }*/

    /** redis地址 */
    @Value("${spring.redis.host}")
    private String host;

    /** redis端口 */
    @Value("${spring.redis.port}")
    private Integer port;

    /** redis密码 */
    @Value("${spring.redis.password}")
    private String password;

    /** redis超时时间 */
    @Value("${spring.redis.timeout}")
    private Integer timeout;

    /**  */
    @Value("${shiro.session.expire}")
    private Integer sessionExpire;

    /**  */
    @Value("${shiro.session.prefix}")
    private String sessionPrefix;

    /** redis缓存过期时间 */
    @Value("${shiro.cache.expire}")
    private Integer cacheExpire;

    /** redis缓存前缀 */
    @Value("${shiro.cache.prefix}")
    private String cachePrefix;

    /** redis缓存后缀 */
    @Value("${shiro.cache.suffix}")
    private String cacheSuffix;

    /** 设置redis选择的库 总共16个库 */
    @Value("${shiro.redis.database}")
    private Integer database;

    /**
     * 设置地址权限的集合
     * anon：无需认证就可以访问
     * authc：必须认证了才能访问
     * user：必须用有了 记住我 功能才能用
     * perms：拥有对某个资源的权限才能访问
     * role：拥有某个角色权限才能访问
     */
    @Value("#{${shiro.filter.map}}")
    public Map<String,String> map = new LinkedHashMap<>();

    /** 未登录跳转的接口地址 */
    @Value("${shiro.login.url}")
    public String loginUrl;

    /**  */
    @Value("${shiro.rememberMe.name}")
    public String rememberMeName;

    @Value("${shiro.rememberMe.maxAge}")
    public Integer maxAge;
}
